/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

class FloatMM {
  public static final int SEEDINIT = 74755;
  public static final int SEED_1309 = 1309;
  public static final int SEED_13849 = 13849;
  public static final int SEED_65535 = 65535;
  public static final int DIVISOR_120 = 120;
  public static final int SUBTRACT_60 = 60;
  public static final int DIVISOR_3 = 3;
  public static final int LOOP_TIMES = 5000;
  public static final int TIME_CONVERSION = 1000;
  public static final int TEST_TIMES = 3;

  /* Intmm, Mm */
  public static int rowsize = 40;

  /* global */
  public static int seed = 0; /* converted to long for 16 bit WR */

  public static double[][] rma = java.util.stream.IntStream.range(0, rowsize + 1).mapToObj(i -> new double[rowsize + 1]).toArray(double[][]::new);
  public static double[][] rmb = java.util.stream.IntStream.range(0, rowsize + 1).mapToObj(i -> new double[rowsize + 1]).toArray(double[][]::new);
  public static double[][] rmr = java.util.stream.IntStream.range(0, rowsize + 1).mapToObj(i -> new double[rowsize + 1]).toArray(double[][]::new);

  public static void initrand() {
    seed = SEEDINIT; /* constant to long WR */
  }

  public static int rand() {
    seed = (seed * SEED_1309 + SEED_13849) & SEED_65535; /* constants to long WR */
    return seed; /* typecast back to int WR */
  }

  /* Multiplies two real matrices. */

  public static void rInitmatrix(double[][] m) {
    int temp;
    for (int i = 1; i <= rowsize; i++) {
      for (int j = 1; j <= rowsize; j++) {
        temp = rand();
        m[i][j] = (temp - Math.floor(temp / DIVISOR_120) * DIVISOR_120 - SUBTRACT_60) / DIVISOR_3;
      }
    }
  }

  public static void rInnerproduct(double[][] result, double[][] a, double[][] b, int row, int column) {
    /* computes the inner product of A[row,*] and B[*,column] */
    result[row][column] = 0.0;
    for (int i = 1; i <= rowsize; i++) {
      result[row][column] = result[row][column] + a[row][i] * b[i][column];
    }
  }

  public static void mm(int run) {
    initrand();

    rInitmatrix(rma);

    rInitmatrix(rmb);
    for (int i = 1; i <= rowsize; i++) {
      for (int j = 1; j <= rowsize; j++) {
        rInnerproduct(rmr, rma, rmb, i, j);
      }
    }
    if (run < rowsize) {
      // System.out.println(rmr[run + 1][run + 1]);
    }
  }
}
/*
   * @State
   * @Tags Jetstream2
   */
  class Benchmark {
    
    public static void runIteration() {
      for (int i = 0; i < FloatMM.LOOP_TIMES; i++) {
        FloatMM.mm(i);
      }
    }

	/**
     * Benchmark
     */
    public static void startRun() {
      double start = System.nanoTime();
      for (int i = 0; i < FloatMM.TEST_TIMES; i++) {
        runIteration();
      }
      double end = System.nanoTime();
      double duration = (end - start) / 1000000;
      System.out.println("float-mm: ms = " + duration);
    }
    public static void main(String[] args) {
      startRun();
    }
  }
 